<?php

declare(strict_types=1);

/*
 * This file is part of PHP CS Fixer.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace PhpCsFixer\Tests\Fixer\Import;

use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
use PhpCsFixer\Fixer\Import\OrderedImportsFixer;
use PhpCsFixer\Tests\Test\AbstractFixerTestCase;

/**
 * @internal
 *
 * @covers \PhpCsFixer\Fixer\Import\OrderedImportsFixer
 *
 * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\Import\OrderedImportsFixer>
 *
 * @phpstan-import-type _AutogeneratedInputConfiguration from \PhpCsFixer\Fixer\Import\OrderedImportsFixer
 *
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
 */
final class OrderedImportsFixerTest extends AbstractFixerTestCase
{
    /**
     * @dataProvider provideFixCases
     *
     * @param _AutogeneratedInputConfiguration $configuration
     */
    public function testFix(string $expected, ?string $input = null, array $configuration = []): void
    {
        $this->fixer->configure($configuration);
        $this->doTest($expected, $input);
    }

    /**
     * @return iterable<string, array{0: string, 1?:null|string, 2?:_AutogeneratedInputConfiguration}>
     */
    public static function provideFixCases(): iterable
    {
        yield 'multiple namespaces' => [
            <<<'EOF'
                <?php

                namespace FooRoo {

                    use Foo\Bar;
                    use Foo\Bar\Foo as Fooo, Foo\Bar\FooBar as FooBaz;
                     use Foo\Bir as FBB;
                    use Foo\Zar\Baz;
                    use SomeClass;
                       use Symfony\Annotation\Template, Zoo\Bar as ZooBar;
                    use Zoo\Tar1;

                    $a = new Bar();
                    $a = new FooBaz();
                    $a = new someclass();

                    use Zoo\Tar2;

                    class AnnotatedClass
                    {
                        /**
                         * @Template(foobar=21)
                         * @param Entity $foo
                         */
                        public function doSomething($foo)
                        {
                            $bar = $foo->toArray();
                            /** @var ArrayInterface $bar */

                            return function () use ($bar, $foo) {};
                        }
                    }
                }

                namespace BlaRoo {

                    use Foo\Zar\Baz;
                  use SomeClass;
                    use Symfony\Annotation\Template;
                  use Symfony\Doctrine\Entities\Entity, Zoo\Bar;

                    class AnnotatedClass
                    {
                        /**
                         * @Template(foobar=21)
                         * @param Entity $foo
                         */
                        public function doSomething($foo)
                        {
                            $bar = $foo->toArray();
                            /** @var ArrayInterface $bar */

                            return function () use ($bar, $foo) {};
                        }
                    }
                }
                EOF,
            <<<'EOF'
                <?php

                namespace FooRoo {

                    use Foo\Bar\FooBar as FooBaz;
                    use Zoo\Bar as ZooBar, Zoo\Tar1;
                     use Foo\Bar;
                    use Foo\Zar\Baz;
                    use Symfony\Annotation\Template;
                       use Foo\Bar\Foo as Fooo, Foo\Bir as FBB;
                    use SomeClass;

                    $a = new Bar();
                    $a = new FooBaz();
                    $a = new someclass();

                    use Zoo\Tar2;

                    class AnnotatedClass
                    {
                        /**
                         * @Template(foobar=21)
                         * @param Entity $foo
                         */
                        public function doSomething($foo)
                        {
                            $bar = $foo->toArray();
                            /** @var ArrayInterface $bar */

                            return function () use ($bar, $foo) {};
                        }
                    }
                }

                namespace BlaRoo {

                    use Foo\Zar\Baz;
                  use Zoo\Bar;
                    use SomeClass;
                  use Symfony\Annotation\Template, Symfony\Doctrine\Entities\Entity;

                    class AnnotatedClass
                    {
                        /**
                         * @Template(foobar=21)
                         * @param Entity $foo
                         */
                        public function doSomething($foo)
                        {
                            $bar = $foo->toArray();
                            /** @var ArrayInterface $bar */

                            return function () use ($bar, $foo) {};
                        }
                    }
                }
                EOF,
        ];

        yield 'multiple namespaces II' => [
            <<<'EOF'
                <?php namespace Space1 {
                    use Foo\Bar\Foo;
                    use Symfony\Annotation\Template;
                }

                namespace Space2 { use A,B; }

                namespace Space3 {
                    use Symfony\Annotation\Template;
                    use Symfony\Doctrine\Entities\Entity0, Zoo\Bar;
                    echo Bar::C;
                    use A\B;
                }

                namespace Space4{}
                EOF,
            <<<'EOF'
                <?php namespace Space1 {
                    use Symfony\Annotation\Template;
                    use Foo\Bar\Foo;
                }

                namespace Space2 { use B,A; }

                namespace Space3 {
                    use Zoo\Bar;
                    use Symfony\Annotation\Template, Symfony\Doctrine\Entities\Entity0;
                    echo Bar::C;
                    use A\B;
                }

                namespace Space4{}
                EOF,
        ];

        yield 'with imports after logic' => [
            '<?php
                use B;
                use C;
                $foo = new C();
                use A;
            ',
            '<?php
                use C;
                use B;
                $foo = new C();
                use A;
            ',
        ];

        yield 'open-close groups' => [
            '
                <?php use X ?>
                <?php use Z ?>
                <?php echo X::class ?>
                <?php use E ?>   output
                <?php use F ?><?php echo E::class; use A; ?>
            ',
            '
                <?php use Z ?>
                <?php use X ?>
                <?php echo X::class ?>
                <?php use F ?>   output
                <?php use E ?><?php echo E::class; use A; ?>
            ',
        ];

        yield 'with comment' => [
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Foo\Bar;
                use Foo\Bar\Foo as Fooo, Foo\Bar\FooBar /* He there */ as FooBaz;
                 use Foo\Bir as FBB;
                use Foo\Zar\Baz;
                use SomeClass;
                   use /* check */Symfony\Annotation\Template, Zoo\Bar as ZooBar;
                use Zoo\Tar;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                class AnnotatedClass
                {
                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Foo\Bar\FooBar /* He there */ as FooBaz;
                use Zoo\Bar as ZooBar, Zoo\Tar;
                 use Foo\Bar;
                use Foo\Zar\Baz;
                use /* check */Symfony\Annotation\Template;
                   use Foo\Bar\Foo as Fooo, Foo\Bir as FBB;
                use SomeClass;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                class AnnotatedClass
                {
                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
        ];

        yield 'with traits' => [
            <<<'EOF'
                <?php

                use Foo\Bar;
                use Foo\Bar\Foo as Fooo, Foo\Bar\FooBar as FooBaz;
                 use Foo\Bir as FBB;
                use Foo\Zar\Baz;
                use SomeClass;
                   use Symfony\Annotation\Template, Zoo\Bar as ZooBar;
                use Zoo\Tar;

                trait Foo {}

                trait Zoo {}

                class AnnotatedClass
                {
                    use Foo, Bar;

                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
            <<<'EOF'
                <?php

                use Foo\Bar\FooBar as FooBaz;
                use Zoo\Bar as ZooBar, Zoo\Tar;
                 use Foo\Bar;
                use Foo\Zar\Baz;
                use Symfony\Annotation\Template;
                   use Foo\Bar\Foo as Fooo, Foo\Bir as FBB;
                use SomeClass;

                trait Foo {}

                trait Zoo {}

                class AnnotatedClass
                {
                    use Foo, Bar;

                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
        ];

        yield 'with trait imports' => [
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Acme\MyReusableTrait;
                use Foo\Bar, Foo\Bar\Foo as Fooo;
                 use Foo\Bar\FooBar as FooBaz;
                use Foo\Bir as FBB;
                use Foo\Zar\Baz;
                use SomeClass;
                   use Symfony\Annotation\Template, Zoo\Bar as ZooBar;
                use Zoo\Tar;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                class AnnotatedClass
                {
                    use MyReusableTrait;

                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $baz) {};
                    }
                }
                EOF,
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Foo\Bar\FooBar as FooBaz;
                use Zoo\Bar as ZooBar, Zoo\Tar;
                 use Foo\Bar;
                use Foo\Zar\Baz;
                use Acme\MyReusableTrait;
                use Symfony\Annotation\Template;
                   use Foo\Bar\Foo as Fooo, Foo\Bir as FBB;
                use SomeClass;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                class AnnotatedClass
                {
                    use MyReusableTrait;

                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $baz) {};
                    }
                }
                EOF,
        ];

        yield 'with different cases' => [
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Baz;
                use abc\Bar;

                <?php

                use abc\Bar;
                use Zoo\Baz;

                class Test
                {
                }
                EOF,
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Baz;
                use abc\Bar;

                <?php

                use Zoo\Baz;
                use abc\Bar;

                class Test
                {
                }
                EOF,
        ];

        yield 'without uses' => [
            <<<'EOF'
                <?php

                $c = 1;
                EOF,
        ];

        yield 'with trailing digits' => [
            <<<'EOF'
                <?php

                use abc\Bar;
                use abc2\Bar2;
                use xyz\abc\Bar6;
                use xyz\abc2\Bar7;
                use xyz\xyz\Bar4;
                use xyz\xyz\Bar5;

                class Test
                {
                }
                EOF,
            <<<'EOF'
                <?php

                use abc2\Bar2;
                use abc\Bar;
                use xyz\abc2\Bar7;
                use xyz\abc\Bar6;
                use xyz\xyz\Bar4;
                use xyz\xyz\Bar5;

                class Test
                {
                }
                EOF,
        ];

        yield 'with imports only' => [
            <<<'EOF'
                <?php

                use Aaa;
                use Bbb;
                EOF,
            <<<'EOF'
                <?php

                use Bbb;
                use Aaa;
                EOF,
        ];

        yield 'with close tag' => [
            '<?php
                use A\C1;
                use A\D?><?php use B\C2; use E\F ?>',
            '<?php
                use A\C1;
                use B\C2?><?php use A\D; use E\F ?>',
        ];

        yield 'with comments' => [
            '<?php
                use A\C1 /* A */;
                use /* B */ B\C2;',
            '<?php
                use /* B */ B\C2;
                use A\C1 /* A */;',
        ];

        yield 'with text before opening tag' => [
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar as ZooBar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Foo\Bar;
                use Foo\Bar\Foo as Fooo, Foo\Bar\FooBar as FooBaz;
                 use Foo\Bir as FBB;
                use Foo\Zar\Baz;
                use SomeClass;
                   use Symfony\Annotation\Template, Zoo\Bar as ZooBar;
                use Zoo\Tar;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                class AnnotatedClass
                {
                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar as ZooBar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Foo\Bar\FooBar as FooBaz;
                use Zoo\Bar as ZooBar, Zoo\Tar;
                 use Foo\Bar;
                use Foo\Zar\Baz;
                use Symfony\Annotation\Template;
                   use Foo\Bar\Foo as Fooo, Foo\Bir as FBB;
                use SomeClass;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                class AnnotatedClass
                {
                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
        ];

        yield 'with grouped import' => [
            '<?php
use A\B;
use some\a\{ClassA, ClassB, ClassC as C};
use some\b\{
    ClassF,
    ClassG
};
use const some\a\{ConstA, ConstB, ConstC};
use const some\b\{
    ConstX,
    ConstY,
    ConstZ
};
use function some\a\{fn_a, fn_b, fn_c};
use function some\b\{
    fn_x,
    fn_y,
    fn_z
};
',
            '<?php
use some\a\{ClassA, ClassB, ClassC as C};
use function some\b\{
    fn_y,
    fn_z,
    fn_x
};
use function some\a\{fn_a, fn_b, fn_c};
use A\B;
use const some\b\{
    ConstZ,
    ConstX,
    ConstY
};
use const some\a\{ConstA, ConstB, ConstC};
use some\b\{
    ClassG,
    ClassF
};
',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => ['class', 'const', 'function'],
            ],
        ];

        yield 'with grouped import and comment' => [
            '<?php
use A\B;
use some\a\{ClassA as A /*z*/, ClassB, ClassC};
use const some\a\{
    ConstA,
    ConstB,
    ConstC
};
use function some\a\{fn_a, fn_b, fn_c};
',
            '<?php
use some\a\{  ClassB,ClassC, /*z*/ ClassA as A};
use function some\a\{fn_c,  fn_a,fn_b   };
use A\B;
use const some\a\{
    ConstA,
    ConstB,
    ConstC
};
',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => ['class', 'const', 'function'],
            ],
        ];

        yield 'with grouped import for classes, constants and functions' => [
            '<?php
use A\B;
use some\a\{ClassA, ClassB, ClassC as C};
use const some\a\{ConstA, ConstB, ConstC};
use function some\a\{fn_a, fn_b, fn_c};
use some\b\{
    ClassF,
    ClassG
};
use const some\b\{
    ConstX,
    ConstY,
    ConstZ
};
use function some\b\{
    fn_x,
    fn_y,
    fn_z
};
',
            '<?php
use some\a\{ClassA, ClassB, ClassC as C};
use function some\b\{
    fn_y,
    fn_z,
    fn_x
};
use function some\a\{fn_a, fn_b, fn_c};
use A\B;
use const some\b\{
    ConstZ,
    ConstX,
    ConstY
};
use const some\a\{ConstA, ConstB, ConstC};
use some\b\{
    ClassG,
    ClassF
};
',
        ];

        yield 'with grouped imports' => [
            '<?php
use A\B;
use const some\a\{
    ConstA,
    ConstB,
    ConstC
};
use some\a\{ClassA as A /*z2*/, ClassB, ClassC};
use function some\a\{fn_a, fn_b, fn_c};
',
            '<?php
use some\a\{  ClassB,ClassC, /*z2*/ ClassA as A};
use function some\a\{fn_c,  fn_a,fn_b   };
use A\B;
use const some\a\{
    ConstA,
    ConstB,
    ConstC
};
',
        ];

        yield 'with order of types' => [
            '<?php
use C\B;
use function B\fn_a;
use const A\ConstA;
            ',
            '<?php
use const A\ConstA;
use function B\fn_a;
use C\B;
            ',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => ['class', 'function', 'const'],
            ],
        ];

        yield 'with imports in the same line and in the new lines' => [
            '<?php
use Foo\Bar\Baz;use Foo\Bar\{ClassA, ClassB, ClassC};
use Foo\Bir;
',
            '<?php
use Foo\Bar\Baz, Foo\Bir;
use Foo\Bar\{ClassC, ClassB, ClassA};
',
        ];

        yield 'many import in single line' => [
            '<?php
use A\A;use Foo3\Bar\{ClassA};use G\G;use H\H;use Ioo2\Bar\{ClassB};use J\J;use K\K;use Loo1\Bar\{ClassC};use M\M;
',
            '<?php
use A\A,G\G;use Foo3\Bar\{ClassA};use H\H,J\J;use Ioo2\Bar\{ClassB};use K\K,M\M;use Loo1\Bar\{ClassC};
',
        ];

        yield 'grouped import changing location to comma separated imports' => [
            <<<'PHP'
                <?php
                use A;
                use B;use C\{C1, C2, C3};use D;
                PHP,
            <<<'PHP'
                <?php
                use C\{C1, C2, C3};
                use D, A, B;
                PHP,
        ];

        yield 'many grouped imports' => [
            '<?php
use Foo\Bar\{ClassA, ClassB, ClassC};
use Foo\Bir\{
    ClassD,
    ClassE,
    ClassF
};
use Foo\Bor\{
    ClassG,
    ClassH,
    ClassI,
    ClassJ
};
',
            '<?php
use Foo\Bar\{ClassC, ClassB, ClassA};
use Foo\Bir\{ClassE, ClassF,
    ClassD};
use Foo\Bor\{
            ClassJ,
                    ClassI,
    ClassH,
                        ClassG
};
',
        ];

        yield 'alpha - [\'class\', \'function\', \'const\']' => [
            '<?php
use Z\Z;
use function X\X;
use const Y\Y;
            ',
            '<?php
use const Y\Y;
use function X\X;
use Z\Z;
            ',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => ['class', 'function', 'const'],
            ],
        ];

        yield 'alpha - [\'class\', \'const\', \'function\']' => [
            '<?php
use Z\Z;
use const Y\Y;
use function X\X;
            ',
            '<?php
use function X\X;
use const Y\Y;
use Z\Z;
            ',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => ['class', 'const', 'function'],
            ],
        ];

        yield 'alpha - [\'function\', \'class\', \'const\']' => [
            '<?php
use function Z\Z;
use Y\Y;
use const X\X;
            ',
            '<?php
use const X\X;
use Y\Y;
use function Z\Z;
            ',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => ['function', 'class', 'const'],
            ],
        ];

        yield 'alpha - [\'function\', \'const\', \'class\']' => [
            '<?php
use function Z\Z;
use const Y\Y;
use X\X;
            ',
            '<?php
use X\X;
use const Y\Y;
use function Z\Z;
            ',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => ['function', 'const', 'class'],
            ],
        ];

        yield 'alpha - [\'const\', \'function\', \'class\']' => [
            '<?php
use const Z\Z;
use function Y\Y;
use X\X;
            ',
            '<?php
use X\X;
use function Y\Y;
use const Z\Z;
            ',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => ['const', 'function', 'class'],
            ],
        ];

        yield 'alpha - [\'const\', \'class\', \'function\']' => [
            '<?php
use const Z\Z;
use Y\Y;
use function X\X;
            ',
            '<?php
use function X\X;
use Y\Y;
use const Z\Z;
            ',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => ['const', 'class', 'function'],
            ],
        ];

        yield '"strcasecmp" vs. "strnatcasecmp"' => [
            '<?php
use A\A1;
use A\A10;
use A\A2;
use A\A20;
            ',
            '<?php
use A\A20;
use A\A2;
use A\A10;
use A\A1;
            ',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
            ],
        ];

        yield 'with trailing comma in single-line grouped import' => [
            '<?php
use A\{B,};
use C\{D,E,};
',
            '<?php
use C\{D,E,};
use A\{B,};
',
        ];

        yield 'with trailing comma in multi-line grouped import' => [
            '<?php
use Foo\{
    Aaa,
    Bbb,
};',
            '<?php
use Foo\{
    Bbb,
    Aaa,
};',
        ];

        yield 'with trailing comma in multi-line grouped import with comments' => [
            '<?php
use Foo\{
    Aaa /* 3 *//* 4 *//* 5 */,
    Bbb /* 1 *//* 2 */,
};',
            '<?php
use Foo\{
    /* 1 */Bbb/* 2 */,/* 3 */
    /* 4 */Aaa/* 5 */,/* 6 */
};',
        ];

        $input = '<?php use A\{B,};
use some\y\{ClassA, ClassB, ClassC as C,};
use function some\a\{fn_a, fn_b, fn_c,};
use const some\Z\{ConstAA,ConstBB,ConstCC,};
use const some\X\{ConstA,ConstB,ConstC,ConstF};
use C\{D,E,};
';

        yield 'with trailing comma in multi-line grouped import - sorting alphabetically' => [
            '<?php use A\{B,};
use C\{D,E,};
use some\y\{ClassA, ClassB, ClassC as C,};
use const some\X\{ConstA,ConstB,ConstC,ConstF};
use const some\Z\{ConstAA,ConstBB,ConstCC,};
use function some\a\{fn_a, fn_b, fn_c,};
',
            $input,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => [OrderedImportsFixer::IMPORT_TYPE_CLASS, OrderedImportsFixer::IMPORT_TYPE_CONST, OrderedImportsFixer::IMPORT_TYPE_FUNCTION],
            ],
        ];

        yield 'with trailing comma in multi-line grouped import - sorting by length' => [
            '<?php use A\{B,};
use C\{D,E,};
use some\y\{ClassA, ClassB, ClassC as C,};
use const some\Z\{ConstAA,ConstBB,ConstCC,};
use const some\X\{ConstA,ConstB,ConstC,ConstF};
use function some\a\{fn_a, fn_b, fn_c,};
',
            $input,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => [OrderedImportsFixer::IMPORT_TYPE_CLASS, OrderedImportsFixer::IMPORT_TYPE_CONST, OrderedImportsFixer::IMPORT_TYPE_FUNCTION],
            ],
        ];

        yield 'with trailing comma in multi-line grouped import - no sorting' => [
            '<?php use A\{B,};
use some\y\{ClassA, ClassB, ClassC as C,};
use C\{D,E,};
use const some\Z\{ConstAA,ConstBB,ConstCC,};
use const some\X\{ConstA,ConstB,ConstC,ConstF};
use function some\a\{fn_a, fn_b, fn_c,};
',
            $input,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_NONE,
                'imports_order' => [OrderedImportsFixer::IMPORT_TYPE_CLASS, OrderedImportsFixer::IMPORT_TYPE_CONST, OrderedImportsFixer::IMPORT_TYPE_FUNCTION],
            ],
        ];

        yield 'only constant imports' => [
            '<?php use const CONST_A, CONST_B, CONST_C;',
            '<?php use const CONST_C, CONST_B, CONST_A;',
        ];

        yield 'only function imports' => [
            '<?php use function Foo\A, Foo\B, Foo\C;',
            '<?php use function Foo\B, Foo\C, Foo\A;',
        ];

        yield 'by length with same length' => [
            <<<'EOF'
                <?php

                use Acme;
                use Bar1;
                use Barr;
                use Fooo;

                class AnnotatedClass
                {
                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
            <<<'EOF'
                <?php

                use Acme;
                use Fooo;
                use Barr;
                use Bar1;

                class AnnotatedClass
                {
                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
            ],
        ];

        yield 'by length with same length and case sensitive' => [
            <<<'EOF'
                <?php

                use Acme;
                use BaRr;
                use Bar1;
                use Fooo;

                class AnnotatedClass { }
                EOF,
            <<<'EOF'
                <?php

                use Acme;
                use Fooo;
                use Bar1;
                use BaRr;

                class AnnotatedClass { }
                EOF,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
                'case_sensitive' => true,
            ],
        ];

        yield 'by length with multiple namespace' => [
            <<<'EOF'
                <?php

                namespace FooRoo {

                    use Foo\Bar;
                    use Zoo\Tar1, Zoo\Tar2;
                    use SomeClass;
                    use Foo\Zar\Baz;
                    use Foo\Bir as FBB;
                    use Zoo\Bar as ZooBar, Foo\Bar\Foo as Fooo;
                    use Foo\Bar\FooBar as FooBaz;

                    use Symfony\Annotation\Template;

                    $a = new Bar();
                    $a = new FooBaz();
                    $a = new someclass();

                    class AnnotatedClass
                    {
                        /**
                         * @Template(foobar=21)
                         * @param Entity $foo
                         */
                        public function doSomething($foo)
                        {
                            $bar = $foo->toArray();
                            /** @var ArrayInterface $bar */

                            return function () use ($bar, $foo) {};
                        }
                    }
                }

                namespace BlaRoo {

                    use Zoo\Bar;
                    use SomeClass;
                    use Foo\Zar\Baz;
                    use Symfony\Annotation\Template, Symfony\Doctrine\Entities\Entity;

                    class AnnotatedClass
                    {
                        /**
                         * @Template(foobar=21)
                         * @param Entity $foo
                         */
                        public function doSomething($foo)
                        {
                            $bar = $foo->toArray();
                            /** @var ArrayInterface $bar */

                            return function () use ($bar, $foo) {};
                        }
                    }
                }
                EOF,
            <<<'EOF'
                <?php

                namespace FooRoo {

                    use Foo\Bar\FooBar as FooBaz;
                    use Zoo\Bar as ZooBar, Zoo\Tar1;
                    use Foo\Bar;
                    use Foo\Zar\Baz;
                    use Symfony\Annotation\Template;
                    use Foo\Bar\Foo as Fooo, Foo\Bir as FBB;
                    use SomeClass;

                    use Zoo\Tar2;

                    $a = new Bar();
                    $a = new FooBaz();
                    $a = new someclass();

                    class AnnotatedClass
                    {
                        /**
                         * @Template(foobar=21)
                         * @param Entity $foo
                         */
                        public function doSomething($foo)
                        {
                            $bar = $foo->toArray();
                            /** @var ArrayInterface $bar */

                            return function () use ($bar, $foo) {};
                        }
                    }
                }

                namespace BlaRoo {

                    use Foo\Zar\Baz;
                    use Zoo\Bar;
                    use SomeClass;
                    use Symfony\Annotation\Template, Symfony\Doctrine\Entities\Entity;

                    class AnnotatedClass
                    {
                        /**
                         * @Template(foobar=21)
                         * @param Entity $foo
                         */
                        public function doSomething($foo)
                        {
                            $bar = $foo->toArray();
                            /** @var ArrayInterface $bar */

                            return function () use ($bar, $foo) {};
                        }
                    }
                }
                EOF,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
            ],
        ];

        yield 'by length with comment' => [
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Foo\Bar;
                use Zoo\Tar, SomeClass;
                use Foo\Zar\Baz;
                use Foo\Bir as FBB;
                use Zoo\Bar as ZooBar;
                use Foo\Bar\Foo as Fooo, Foo\Bar\FooBar /* He there */ as FooBaz;
                use /* FIXME */Symfony\Annotation\Template;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                use Symfony\Doctrine\Entities\Entity;

                class AnnotatedClass
                {
                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Foo\Bar\FooBar /* He there */ as FooBaz;
                use Zoo\Bar as ZooBar, Zoo\Tar;
                use Foo\Bar;
                use Foo\Zar\Baz;
                use /* FIXME */Symfony\Annotation\Template;
                use Foo\Bar\Foo as Fooo, Foo\Bir as FBB;
                use SomeClass;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                use Symfony\Doctrine\Entities\Entity;

                class AnnotatedClass
                {
                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
            ],
        ];

        yield 'by length' => [
            <<<'EOF'
                <?php

                use Foo\Bar;
                use Zoo\Tar, SomeClass;
                use Foo\Zar\Baz;
                use Foo\Bir as FBB;
                use Zoo\Bar as ZooBar;
                use Foo\Bar\Foo as Fooo, Foo\Bar\FooBar as FooBaz;
                use Symfony\Annotation\Template;

                use Symfony\Doctrine\Entities\Entity;

                trait Foo {}

                trait Zoo {}

                class AnnotatedClass
                {
                    use Foo, Bar;

                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
            <<<'EOF'
                <?php

                use Foo\Bar\FooBar as FooBaz;
                use Zoo\Bar as ZooBar, Zoo\Tar;
                use Foo\Bar;
                use Foo\Zar\Baz;
                use Symfony\Annotation\Template;
                use Foo\Bar\Foo as Fooo, Foo\Bir as FBB;
                use SomeClass;

                use Symfony\Doctrine\Entities\Entity;

                trait Foo {}

                trait Zoo {}

                class AnnotatedClass
                {
                    use Foo, Bar;

                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
            ],
        ];

        yield 'by length with trait imports' => [
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Foo\Bar;
                use Zoo\Tar, SomeClass;
                use Foo\Zar\Baz;
                use Foo\Bir as FBB;
                use Zoo\Bar as ZooBar;
                use Foo\Bar\Foo as Fooo;
                use Acme\MyReusableTrait, Foo\Bar\FooBar as FooBaz;
                use Symfony\Annotation\Template;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                use Symfony\Doctrine\Entities\Entity;

                class AnnotatedClass
                {
                    use MyReusableTrait;

                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $baz) {};
                    }
                }
                EOF,
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Foo\Bar\FooBar as FooBaz;
                use Zoo\Bar as ZooBar, Zoo\Tar;
                use Foo\Bar;
                use Foo\Zar\Baz;
                use Acme\MyReusableTrait;
                use Symfony\Annotation\Template;
                use Foo\Bar\Foo as Fooo, Foo\Bir as FBB;
                use SomeClass;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                use Symfony\Doctrine\Entities\Entity;

                class AnnotatedClass
                {
                    use MyReusableTrait;

                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $baz) {};
                    }
                }
                EOF,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
            ],
        ];

        yield 'by length with different cases' => [
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Baz;
                use abc\Bar;

                <?php

                use abc\Bar;
                use Zoo\Baz;

                class Test
                {
                }
                EOF,
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Baz;
                use abc\Bar;

                <?php

                use Zoo\Baz;
                use abc\Bar;

                class Test
                {
                }
                EOF,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
            ],
        ];

        yield 'by length order with trailing digit' => [
            <<<'EOF'
                <?php

                use abc\Bar;
                use abc2\Bar2;
                use xyz\abc\Bar6;
                use xyz\xyz\Bar4;
                use xyz\xyz\Bar5;
                use xyz\abc2\Bar7;

                class Test
                {
                }
                EOF,
            <<<'EOF'
                <?php

                use abc2\Bar2;
                use abc\Bar;
                use xyz\abc2\Bar7;
                use xyz\abc\Bar6;
                use xyz\xyz\Bar4;
                use xyz\xyz\Bar5;

                class Test
                {
                }
                EOF,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
            ],
        ];

        yield 'by length code with imports only' => [
            <<<'EOF'
                <?php

                use Aaa;
                use Bbb;
                EOF,
            <<<'EOF'
                <?php

                use Bbb;
                use Aaa;
                EOF,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
            ],
        ];

        yield 'by length without uses' => [
            <<<'EOF'
                <?php

                $c = 1;
                EOF,
            null,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
            ],
        ];

        yield 'by length 2' => [
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar as ZooBar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Foo\Bar;
                use Zoo\Tar, SomeClass;
                 use Foo\Zar\Baz;
                use Foo\Bir as FBB;
                use Zoo\Bar as ZooBar;
                   use Foo\Bar\Foo as Fooo, Foo\Bar\FooBar as FooBaz;
                use Symfony\Annotation\Template;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                use Symfony\Doctrine\Entities\Entity;

                class AnnotatedClass
                {
                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar as ZooBar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Foo\Bar\FooBar as FooBaz;
                use Zoo\Bar as ZooBar, Zoo\Tar;
                 use Foo\Bar;
                use Foo\Zar\Baz;
                use Symfony\Annotation\Template;
                   use Foo\Bar\Foo as Fooo, Foo\Bir as FBB;
                use SomeClass;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                use Symfony\Doctrine\Entities\Entity;

                class AnnotatedClass
                {
                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
            ],
        ];

        yield 'by length 3' => [
            '<?php
use A\B;
use Foo\Bar\Biz;
use some\b\{
    ClassF,
    ClassG
};
use function some\a\{fn_a, fn_b, fn_c};
use some\b\{ClassA, ClassB, ClassC as C};
use const some\a\{ConstA, ConstB, ConstC};
use some\a\{ClassX as X /*z*/, ClassY, ClassZ};
use Some\Biz\Barz\Boozz\Foz\Which\Is\Really\Long;
use const some\b\{ConstG, ConstX, ConstY, ConstZ};
use some\c\{ClassR, ClassT, ClassV as V, NiceClassName};
',
            '<?php
use function some\a\{fn_a, fn_b, fn_c};
use Foo\Bar\Biz;
use some\c\{ClassR, ClassT, ClassV as V, NiceClassName};
use A\B;
use Some\Biz\Barz\Boozz\Foz\Which\Is\Really\Long;
use some\b\{
    ClassF,
    ClassG
};
use const some\a\{ConstB, ConstA, ConstC};
use const some\b\{ConstX, ConstY, ConstZ, ConstG};
use some\b\{ClassA, ClassB, ClassC as C};
use some\a\{  ClassY,ClassZ, /*z*/ ClassX as X};
',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
            ],
        ];

        yield 'without types order' => [
            '<?php
use const ZZZ;
use function B;
use function A123;
',
            '<?php
use function B;
use function A123;
use const ZZZ;
',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => null,
            ],
        ];

        yield 'types order and length' => [
            '<?php
use A\B;
use Some\Bar;
use Foo\Zar\Baz;
use some\b\{
    ClassF,
    ClassG
};
use some\a\{ClassA, ClassB, ClassC as C};
use some\b\{ClassK, ClassL, ClassM as M};
use some\a\{ClassX as X /*z*/, ClassY, ClassZ};
use const some\a\{ConstA, ConstB, ConstC};
use const some\b\{ConstD, ConstE, ConstF};
use function some\a\{fn_a, fn_b};
use function some\f\{fn_c, fn_d, fn_e};
use function some\b\{fn_k, fn_l, func_m};
',
            '<?php
use const some\a\{ConstA, ConstB, ConstC};
use some\a\{ClassA, ClassB, ClassC as C};
use Foo\Zar\Baz;
use some\b\{ClassK, ClassL, ClassM as M};
use some\a\{ClassX as X /*z*/, ClassY, ClassZ};
use A\B;
use some\b\{
    ClassF,
    ClassG
};
use function some\b\{fn_k, fn_l, func_m};
use Some\Bar;
use function some\a\{fn_a, fn_b};
use const some\b\{ConstD, ConstE, ConstF};
use function some\f\{fn_c, fn_d, fn_e};
',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_LENGTH,
                'imports_order' => [OrderedImportsFixer::IMPORT_TYPE_CLASS, OrderedImportsFixer::IMPORT_TYPE_CONST, OrderedImportsFixer::IMPORT_TYPE_FUNCTION],
            ],
        ];

        yield 'types order and alphabet' => [
            '<?php
use Aaa\Bbb;
use Aaa\Ccc;
use Bar\Biz\Boooz\Bum;
use Foo\Zar\Baz;
use some\a\{ClassA};
use some\b\{
    ClassF,
    ClassG
};
use some\b\{ClassB, ClassC as C, ClassD};
use Some\Cloz;
use const some\a\{ConstA};
use const some\a\{ConstB, ConstC as CC};
use const some\a\{ConstD};
use const some\b\{ConstE};
use function some\a\{fn_a, fn_b};
use function some\a\{fn_bc};
use function some\b\{fn_c, fn_d, fn_e};
use function some\c\{fn_f};
use function some\f\{fn_g, fn_h, fn_i};
',
            '<?php
use Aaa\Ccc;
use Foo\Zar\Baz;
use function some\f\{fn_g, fn_h, fn_i};
use some\a\{ClassA};
use some\b\{ClassD, ClassB, ClassC as C};
use Bar\Biz\Boooz\Bum;
use function some\c\{fn_f};
use some\b\{
    ClassF,
    ClassG
};
use const some\a\{ConstD};
use Some\Cloz;
use function some\a\{fn_bc};
use const some\a\{ConstA};
use function some\b\{fn_c, fn_d, fn_e};
use const some\a\{ConstB, ConstC as CC};
use Aaa\Bbb;
use const some\b\{ConstE};
use function some\a\{fn_a, fn_b};
',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => [OrderedImportsFixer::IMPORT_TYPE_CLASS, OrderedImportsFixer::IMPORT_TYPE_CONST, OrderedImportsFixer::IMPORT_TYPE_FUNCTION],
            ],
        ];

        yield 'types order and none' => [
            '<?php
use Aaa\Ccc;
use Foo\Zar\Baz;
use some\a\{ClassA};
use some\b\{ClassD, ClassB, ClassC as C};
use Bar\Biz\Boooz\Bum;
use some\b\{
    ClassF,
    ClassG
};
use Some\Cloz;
use Aaa\Bbb;
use const some\a\{ConstD};
use const some\a\{ConstA};
use const some\a\{ConstB, ConstC as CC};
use const some\b\{ConstE};
use function some\f\{fn_g, fn_h, fn_i};
use function some\c\{fn_f};
use function some\a\{fn_x};
use function some\b\{fn_c, fn_d, fn_e};
use function some\a\{fn_a, fn_b};
',
            '<?php
use Aaa\Ccc;
use Foo\Zar\Baz;
use function some\f\{fn_g, fn_h, fn_i};
use some\a\{ClassA};
use some\b\{ClassD, ClassB, ClassC as C};
use Bar\Biz\Boooz\Bum;
use function some\c\{fn_f};
use some\b\{
    ClassF,
    ClassG
};
use const some\a\{ConstD};
use Some\Cloz;
use function some\a\{fn_x};
use const some\a\{ConstA};
use function some\b\{fn_c, fn_d, fn_e};
use const some\a\{ConstB, ConstC as CC};
use Aaa\Bbb;
use const some\b\{ConstE};
use function some\a\{fn_a, fn_b};
',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_NONE,
                'imports_order' => [OrderedImportsFixer::IMPORT_TYPE_CLASS, OrderedImportsFixer::IMPORT_TYPE_CONST, OrderedImportsFixer::IMPORT_TYPE_FUNCTION],
            ],
        ];

        yield 'by none' => [
            <<<'EOF'
                The normal
                use of this fixer
                should not change this sentence nor those statements below
                use Zoo\Bar as ZooBar;
                use Foo\Bar;
                use Foo\Zar\Baz;

                <?php

                use Foo\Bar\FooBar as FooBaz;
                use Zoo\Bar as ZooBar, Zoo\Tar;
                 use Foo\Bar;
                use Foo\Zar\Baz;
                use Symfony\Annotation\Template;
                   use Foo\Bar\Foo as Fooo, Foo\Bir as FBB;
                use SomeClass;

                $a = new Bar();
                $a = new FooBaz();
                $a = new someclass();

                use Symfony\Doctrine\Entities\Entity;

                class AnnotatedClass
                {
                    /**
                     * @Template(foobar=21)
                     * @param Entity $foo
                     */
                    public function doSomething($foo)
                    {
                        $bar = $foo->toArray();
                        /** @var ArrayInterface $bar */

                        return function () use ($bar, $foo) {};
                    }
                }
                EOF,
            null,
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_NONE,
                'imports_order' => null,
            ],
        ];

        yield 'with case sensitive' => [
            <<<'EOF'
                <?php

                use AA;
                use Aaa;

                class Foo { }
                EOF,
            <<<'EOF'
                <?php

                use Aaa;
                use AA;

                class Foo { }
                EOF,
            [
                'case_sensitive' => true,
            ],
        ];

        yield 'do not take the braces in grouped imports into account' => [
            <<<'PHP'
                <?php
                use Foo\{Alfa, Alfa2};
                use Foo\Bravo;
                use Foo\{Delta, Delta2};
                use Foo\Foxtrot\Uniform\Charlie\Kilo;
                use Foo\November\{Golf, Juliett};
                use Foo\November\Hotel;
                use Foo\{Yankee007, Yankee42, Yankee99};
                use Foo\{Zulu, Zulu2};
                PHP,
            <<<'PHP'
                <?php
                use Foo\{Zulu, Zulu2};
                use Foo\{Delta2, Delta};
                use Foo\{Alfa, Alfa2};
                use Foo\{Yankee99, Yankee42, Yankee007};
                use Foo\Bravo;
                use Foo\Foxtrot\Uniform\Charlie\Kilo;
                use Foo\November\Hotel;
                use Foo\November\{Juliett, Golf};
                PHP,
        ];
    }

    /**
     * @requires PHP <8.0
     */
    public function testFixPre80(): void
    {
        $this->doTest(
            '<?php
                    use#
A\C1;
                    use B#
\C2#
#
;',
            '<?php
                    use#
B#
\C2#
#
;
                    use A\C1;'
        );
    }

    /**
     * @param array<string, mixed> $wrongConfig
     *
     * @dataProvider provideInvalidConfigurationCases
     */
    public function testInvalidConfiguration(string $expectedMessage, array $wrongConfig): void
    {
        $this->expectException(InvalidFixerConfigurationException::class);
        $this->expectExceptionMessage($expectedMessage);

        $this->fixer->configure($wrongConfig);
    }

    /**
     * @return iterable<string, array{string, array<string, mixed>}>
     */
    public static function provideInvalidConfigurationCases(): iterable
    {
        yield 'unknown order types' => [
            '[ordered_imports] Invalid configuration: Unknown sort types "foo" and "bar".',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => ['class', 'const', 'function', 'foo', 'bar'],
            ],
        ];

        yield 'invalid order types size' => [
            '[ordered_imports] Invalid configuration: Missing sort type "function".',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => ['class', 'const'],
            ],
        ];

        yield 'invalid order type' => [
            '[ordered_imports] Invalid configuration: Missing sort type "class".',
            [
                'sort_algorithm' => OrderedImportsFixer::SORT_ALPHA,
                'imports_order' => ['const', 'function', 'bar'],
            ],
        ];

        yield 'invalid sort algorithm' => [
            '[ordered_imports] Invalid configuration: The option "sort_algorithm" with value "dope" is invalid. Accepted values are: "alpha", "length", "none".',
            [
                'sort_algorithm' => 'dope',
                'imports_order' => null,
            ],
        ];

        yield 'invalid sort algorithm 2' => [
            '[ordered_imports] Invalid configuration: The option "sort_algorithm" with value array is invalid. Accepted values are: "alpha", "length", "none".',
            [
                'sort_algorithm' => [OrderedImportsFixer::SORT_ALPHA, OrderedImportsFixer::SORT_LENGTH],
                'imports_order' => null,
            ],
        ];

        yield 'invalid sort algorithm 3' => [
            '[ordered_imports] Invalid configuration: The option "sort_algorithm" with value stdClass is invalid. Accepted values are: "alpha", "length", "none".',
            [
                'sort_algorithm' => new \stdClass(),
                'imports_order' => null,
            ],
        ];
    }
}
